<template>
  <div class="canvas-editor">
    <div class="canvas-container">
      <canvas id="canvas"></canvas>
    </div>
    <div class="layer-container">
      <layer-control 
        ref="layerControl"
        :layers="layers" 
        @select-layer="selectLayer" 
        @delete-layer="deleteLayer" 
        @add-layer="addLayer"
        @add-layout="addLayout"
        @move-layer-up="moveLayerUp" 
        @move-layer-down="moveLayerDown"
        @group-layer="groupLayer"
        @reorder-layer="reorderLayer"
        @update-layer-name="updateLayerName"
        @toggle-layer-visibility="toggleLayerVisibility"
        @toggle-layer-lock="toggleLayerLock"
        />
    </div>
  </div>
</template>

<script>
import { fabric } from 'fabric';
import LayerControl from './LayerControl.vue';

export default {
  name: 'CanvasEditor',
  components: {
    LayerControl
  },
  data() {
    return {
      canvas: null,
      layers: [],
      selectedLayerKey: null
    };
  },
  mounted() {
    this.canvas = new fabric.Canvas('canvas', {
      width: 600,
      height: 400,
      backgroundColor: '#fff'
    });
    // 控件手柄样式：蓝色边框白色方块
    fabric.Object.prototype.cornerColor = 'rgba(0,0,0,0)'; // 填充色
    fabric.Object.prototype.cornerStrokeColor = 'rgb(206,223,255)'; // 边框色
    fabric.Object.prototype.cornerSize = 8;
    fabric.Object.prototype.cornerStyle = 'rect';
    fabric.Object.prototype.transparentCorners = false;
    // 默认未选中为灰色虚线
    fabric.Object.prototype.borderColor = 'rgb(98,139,245)';
    fabric.Object.prototype.borderDashArray = [5, 5];
    // 确保所有对象都不受显示范围限制
    fabric.Object.prototype.clipPath = null;
    fabric.Object.prototype.subTargetCheck = false;
    // 确保Group对象不限制子对象显示范围
    fabric.Group.prototype.clipPath = null;
    fabric.Group.prototype.subTargetCheck = false;
    fabric.Group.prototype.absolutePositioned = false;
    this.canvas.on('object:added', this.updateLayers);
    this.canvas.on('object:removed', this.updateLayers);
    this.canvas.on('object:modified', this.updateLayers);
    this.canvas.on('object:modified', this.updateLayoutBounds);
    this.canvas.on('selection:created', this.handleSelectionChange);
    this.canvas.on('selection:updated', this.handleSelectionChange);
    this.canvas.on('selection:cleared', this.handleSelectionChange);
    this.canvas.on('selection:created', this.handleBorderStyleOnSelect);
    this.canvas.on('selection:updated', this.handleBorderStyleOnSelect);
    this.canvas.on('selection:cleared', this.handleBorderStyleOnClear);
    this.canvas.on('after:render', this.updateLayers);
    this.updateLayers();
    // 确保所有layout都不受显示范围限制
    this.removeAllLayoutRestrictions();
  },
  methods: {
    handleSelectionChange() {
      const activeObject = this.canvas.getActiveObject();

      if (activeObject && activeObject.type !== 'activeSelection' && activeObject.id) {
        this.$refs.layerControl.$refs.layerTree.setCurrentKey(activeObject.id);
      } else {
        this.$refs.layerControl.$refs.layerTree.setCurrentKey(null);
      }
      
      // 更新layout手柄显示状态
      this.updateLayoutHandles();
    },
    handleBorderStyleOnSelect(e) {
      // 只处理单选
      let objs = [];
      if (e && e.selected) {
        objs = e.selected;
      } else if (this.canvas.getActiveObject()) {
        objs = [this.canvas.getActiveObject()];
      }
      objs.forEach(obj => {
        obj.set({
          borderColor: '#409EFF', // 蓝色
          borderDashArray: null
        });
      });
      this.canvas.requestRenderAll();
    },
    handleBorderStyleOnClear() {
      // 所有对象恢复为灰色虚线
      this.canvas.getObjects().forEach(obj => {
        obj.set({
          borderColor: '#f2f2f2',
          borderDashArray: [5, 5]
        });
      });
      // group（layout）内部的子对象也要恢复
      this.canvas.getObjects().forEach(obj => {
        if (obj.isLayout && obj.getObjects) {
          obj.getObjects().forEach(child => {
            child.set({
              borderColor: '#f2f2f2',
              borderDashArray: [5, 5]
            });
          });
        }
      });
      this.canvas.requestRenderAll();
    },
    addLayer() {
      const id = 'layer_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
      const name = `Layer ${this.canvas.getObjects().length + 1}`;
      const rectWidth = 100;
      const rectHeight = 100;
      // 居中计算
      const canvasWidth = this.canvas.getWidth();
      const canvasHeight = this.canvas.getHeight();
      const left = (canvasWidth - rectWidth) / 2;
      const top = (canvasHeight - rectHeight) / 2;
      const rect = new fabric.Rect({
        left,
        top,
        fill: this.getRandomColor(),
        width: rectWidth,
        height: rectHeight,
        name,
        // 确保不受显示范围限制
        clipPath: null,
        subTargetCheck: false
      });
      rect.id = id;
      rect.isVisible = true;
      this.canvas.add(rect);
      this.canvas.setActiveObject(rect);
      this.canvas.renderAll();
      this.$nextTick(() => {
        this.$refs.layerControl.$refs.layerTree.setCurrentKey(id);
      });
    },
    addLayout() {
      const activeObjects = this.canvas.getActiveObjects();
      if (activeObjects.length === 0) {
        alert('Please select one or more layers to create a layout.');
        return;
      }
      if (activeObjects.some(obj => obj.isLayout)) {
        alert('Cannot group a layout.');
        return;
      }

      // 1. 手动计算选中对象的总体包围盒
      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
      activeObjects.forEach(obj => {
        const rect = obj.getBoundingRect();
        minX = Math.min(minX, rect.left);
        minY = Math.min(minY, rect.top);
        maxX = Math.max(maxX, rect.left + rect.width);
        maxY = Math.max(maxY, rect.top + rect.height);
      });
      const layoutWidth = maxX - minX;
      const layoutHeight = maxY - minY;

      const id = 'layout_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
      const layoutName = `Layout ${this.canvas.getObjects().length + 1}`;

      // 2. 在计算好的位置创建一个空的 Layout
      const newLayout = new fabric.Group([], {
        id,
        name: layoutName,
        isLayout: true,
        left: minX,
        top: minY,
        width: layoutWidth,
        height: layoutHeight,
        originX: 'left',
        originY: 'top',
      });

      // 3. 将对象逐个添加到 Layout 中，并精确设置其本地坐标
      activeObjects.forEach(obj => {
        const objRect = obj.getBoundingRect();
        this.canvas.remove(obj);
        newLayout.add(obj);
        obj.set({
          left: objRect.left - minX,
          top: objRect.top - minY,
        });
      });

      this.canvas.add(newLayout);
      newLayout.setCoords();
      this.canvas.discardActiveObject();
      this.canvas.setActiveObject(newLayout);

      this.$nextTick(() => {
        if (this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree) {
          this.$refs.layerControl.$refs.layerTree.setCurrentKey(id);
        }
        this.updateLayoutHandles();
        this.updateLayoutBounds();
        this.canvas.renderAll();
      });
    },
    deleteLayer(layer) {
      if (layer.isLayout && layer.getObjects) {
        // 只移除group本身，子layer平移到canvas根目录
        const objects = layer.getObjects();
        const children = objects; // 不再 slice(1)，全部都是用户 layer
        children.forEach(child => {
          // 计算全局坐标 - 使用fabric.js的getBoundingRect方法获取准确的全局位置
          const childRect = child.getBoundingRect();
          child.set({ 
            left: childRect.left, 
            top: childRect.top 
          });
          this.canvas.add(child);
        });
        this.canvas.remove(layer);
        this.canvas.discardActiveObject();
        this.canvas.renderAll();
        this.updateLayers();
        this.updateLayoutBounds();
        return;
      }
      // 普通layer
      if (layer.group) {
        layer.group.removeWithUpdate(layer);
      }
      this.canvas.remove(layer);
      this.canvas.discardActiveObject();
      this.canvas.renderAll();
      this.updateLayers();
      this.updateLayoutBounds();
    },
    selectLayer(layer) {
      this.canvas.setActiveObject(layer);
      this.canvas.renderAll();
      if (this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree) {
        this.$refs.layerControl.$refs.layerTree.setCurrentKey(layer.id);
      }
      // 新增：当选中 layout 时，才更新其包围盒
      if (layer && layer.isLayout) {
        this.updateLayoutBounds();
      }
      // 更新layout手柄显示状态
      this.updateLayoutHandles();
    },
    updateLayers() {
      // 记录当前已展开的layout id
      let expandedKeys = [];
      if (this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree) {
        const tree = this.$refs.layerControl.$refs.layerTree;
        if (tree.store && tree.store._getAllNodes) {
          expandedKeys = tree.store._getAllNodes().filter(n => n.expanded).map(n => n.key);
        }
      }

      const buildLayerTree = (fabricObjects) => {
        return fabricObjects
          .filter(obj => obj.id) // 只递归有id的对象，排除外层Rect
          .map((obj, index) => {
            const isLayout = obj.isLayout;
            const name = obj.get('name') || `Layer ${index + 1}`;
            let children = [];
            if (isLayout && obj.getObjects) {
              const groupObjects = obj.getObjects();
              children = groupObjects.length > 0 ? buildLayerTree(groupObjects) : [];
            }
            return {
              id: obj.id,
              name,
              fabricObject: obj,
              isLayout,
              isVisible: obj.visible,
              children,
            };
          }).reverse();
      };
      this.layers = buildLayerTree(this.canvas.getObjects());

      // 保证每个 layout 的外层 Rect 和子 layer 的显示状态同步
      this.canvas.getObjects().forEach(obj => {
        if (obj.isLayout && obj.getObjects) {
          const objects = obj.getObjects();
          const rect = objects[0];
          const children = objects.slice(1);
          if (rect) {
            rect.visible = children.some(child => child.visible);
          }
          // 同步子对象的 hasControls/hasBorders
          children.forEach(child => {
            child.set({
              hasControls: child.visible,
              hasBorders: child.visible
            });
          });
        }
      });
      this.canvas.requestRenderAll();

      // 恢复展开状态
      this.$nextTick(() => {
        const tree = this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree;
        if (tree && expandedKeys.length) {
          expandedKeys.forEach(key => {
            const node = tree.getNode(key);
            if (node) node.expanded = true;
          });
        }
        // 折叠所有没有子layer的layout
        function checkAndCollapse(node) {
          if (node.isLayout) {
            if (!node.children || node.children.length === 0) {
              if (tree) {
                const treeNode = tree.getNode(node.id);
                if (treeNode) treeNode.expanded = false;
              }
            }
          }
          if (node.children && node.children.length) {
            node.children.forEach(checkAndCollapse);
          }
        }
        this.layers.forEach(checkAndCollapse);
        if (tree) {
          tree.$forceUpdate();
        }
      });
      
      // 更新layout手柄显示状态
      this.updateLayoutHandles();
    },
    moveLayerUp(layer) {
        this.canvas.bringForward(layer);
        this.updateLayers();
        this.canvas.renderAll();
        this.updateLayoutBounds();
    },
    moveLayerDown(layer) {
        this.canvas.sendBackwards(layer);
        this.updateLayers();
        this.canvas.renderAll();
        this.updateLayoutBounds();
    },
    groupLayer({ layer, group }) {
      if (!layer || !group || layer.group === group) return;
      if (layer.isLayout) return;

      // 1. 获取 layer 的全局中心点
      const layerCenter = layer.getCenterPoint();
      // 2. 用 group 的 toLocalPoint 算出 layer 在 group 内的本地坐标（都用 center）
      const localPoint = group.toLocalPoint(layerCenter, 'center', 'center');
      // 3. 设置 layer 的 left/top/originX/originY
      layer.set({
        left: localPoint.x,
        top: localPoint.y,
        originX: 'center',
        originY: 'center'
      });

      this.canvas.remove(layer);
      if (layer.group) {
        layer.group.removeWithUpdate(layer);
        layer.group.setCoords();
      }

      group.addWithUpdate(layer);

      // 确保layout不会限制子图层的显示范围
      group.set({
        clipPath: null,
        subTargetCheck: false,
        absolutePositioned: false,
        clipTo: null,
        allowTouchScrolling: false,
        lockScalingFlip: false,
        lockRotation: false,
        lockMovementX: false,
        lockMovementY: false
      });

      // Update the new group's layout
      group.setCoords();
      this.canvas.sendToBack(group); // 保证 layout 始终在最底层

      this.canvas.renderAll();
      this.updateLayers();
      // 移除强制更新，等待用户点击 layout 时再更新
      // this.updateLayoutBounds(group.id); 
    },
    reorderLayer({ layer, targetLayer, dropType }) {
      // Handle ungrouping
      if (layer.group && (dropType === 'before' || dropType === 'after')) {
        const oldGroup = layer.group;
        oldGroup.removeWithUpdate(layer);

        // Update the old group's layout
        oldGroup.setCoords();
        // 移除强制更新
        // this.updateLayoutBounds(oldGroup.id);

        // 使用getBoundingRect获取准确的全局位置
        const layerRect = layer.getBoundingRect();
        // 恢复全局坐标
        layer.set({
            left: layerRect.left,
            top: layerRect.top,
            originX: 'left',
            originY: 'top'
        });
        
        this.canvas.add(layer);
      }
      
      const targetIndex = this.canvas.getObjects().indexOf(targetLayer);
      this.canvas.moveTo(layer, dropType === 'before' ? targetIndex : targetIndex + 1);
      // 如果目标是 layout，保证 layout 在最底层
      if (targetLayer.isLayout) {
        this.canvas.sendToBack(targetLayer);
      }
      this.updateLayers();
      this.canvas.renderAll();
      this.updateLayoutBounds();
    },
    getRandomColor() {
        const letters = '0123456789ABCDEF';
        let color = '#';
        for (let i = 0; i < 6; i++) {
            color += letters[Math.floor(Math.random() * 16)];
        }
        return color;
    },
    updateLayerName({ id, newName }) {
      const target = this.findObjectById(id);
      if (target) {
        target.set('name', newName);
        this.canvas.renderAll();
        // After updating the name, we must refresh the entire layers array
        // to ensure the change is reflected in the child component's UI.
        this.updateLayers();
      }
    },
    toggleLayerVisibility({ id }) {
      const target = this.findObjectById(id);
      if (!target) return;
      // 如果是布局，递归切换所有子图层的可见性
      if (target.isLayout && target.getObjects) {
        const children = target.getObjects().slice(1); // 跳过外层Rect
        // 判断当前是否有可见子图层
        const anyVisible = children.some(child => child.visible);
        // 如果有可见子图层，则全部隐藏，否则全部显示
        children.forEach(child => {
          child.set('visible', !anyVisible);
          child.isVisible = child.visible;
          child.set({
            hasControls: child.visible,
            hasBorders: child.visible
          });
        });
        // 外层Rect的visible由updateLayers统一处理
      } else {
        // 普通图层直接切换
        target.set('visible', !target.visible);
        target.isVisible = target.visible;
        target.set({
          hasControls: target.visible,
          hasBorders: target.visible
        });
      }
      this.canvas.renderAll();
      this.updateLayers();
    },
    findObjectById(id) {
      const search = (objs) => {
        for (const obj of objs) {
          if (obj.id === id) return obj;
          if (obj.isLayout && obj.getObjects) {
            const res = search(obj.getObjects());
            if (res) return res;
          }
        }
        return null;
      };
      return search(this.canvas.getObjects());
    },
    toggleLayerLock({ id, locked }) {
      const target = this.findObjectById(id);
      if (!target) return;
      target.locked = locked;
      target.set({
        lockMovementX: locked,
        lockMovementY: locked,
        selectable: !locked,
        evented: !locked
      });
      this.canvas.discardActiveObject();
      this.canvas.renderAll();
      this.updateLayers();
    },
    updateLayoutBounds() {
      // 只在 layout 被 el-tree 选中时才更新 group 的包围盒，否则不动
      let selectedLayoutId = null;
      if (this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree) {
        selectedLayoutId = this.$refs.layerControl.$refs.layerTree.getCurrentKey();
      }
      this.canvas.getObjects().forEach(obj => {
        if (obj.isLayout && obj.getObjects) {
          // 只处理被选中的 layout
          if (obj.id === selectedLayoutId) {
            const children = obj.getObjects();
            if (children.length > 0) {
              // 计算所有子 layer 的全局包围盒
              let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
              children.forEach(child => {
                const rect = child.getBoundingRect(); // 全局坐标
                minX = Math.min(minX, rect.left);
                minY = Math.min(minY, rect.top);
                maxX = Math.max(maxX, rect.left + rect.width);
                maxY = Math.max(maxY, rect.top + rect.height);
              });
              // 设置 group 的 left/top/width/height
              obj.set({
                left: minX,
                top: minY,
                width: maxX - minX,
                height: maxY - minY
              });
            }
            obj.setCoords();
          }
          obj.set({
            clipPath: null,
            subTargetCheck: false,
            absolutePositioned: false,
            clipTo: null,
            allowTouchScrolling: false,
            lockScalingFlip: false,
            lockRotation: false,
            lockMovementX: false,
            lockMovementY: false
          });
        }
      });
      this.canvas.requestRenderAll();
    },
    removeAllLayoutRestrictions() {
      // 确保所有layout和子对象都不受显示范围限制
      this.canvas.getObjects().forEach(obj => {
        // 移除所有对象的显示范围限制
        obj.set({
          clipPath: null,
          subTargetCheck: false,
          absolutePositioned: false,
          clipTo: null,
          allowTouchScrolling: false,
          lockScalingFlip: false,
          lockRotation: false,
          lockMovementX: false,
          lockMovementY: false
        });
        
        // 如果是layout，确保其子对象也不受限制
        if (obj.isLayout && obj.getObjects) {
          obj.getObjects().forEach(child => {
            child.set({
              clipPath: null,
              subTargetCheck: false,
              absolutePositioned: false,
              clipTo: null,
              allowTouchScrolling: false,
              lockScalingFlip: false,
              lockRotation: false,
              lockMovementX: false,
              lockMovementY: false
            });
          });
        }
      });
      
      this.canvas.requestRenderAll();
    },
    updateLayoutHandles() {
      // 获取当前在图层树中选中的对象ID
      let selectedTreeKey = null;
      if (this.$refs.layerControl && this.$refs.layerControl.$refs.layerTree) {
        selectedTreeKey = this.$refs.layerControl.$refs.layerTree.getCurrentKey();
      }
      // 遍历所有layout，根据是否在图层树中被选中来控制手柄显示和拖动属性
      this.canvas.getObjects().forEach(obj => {
        if (obj.isLayout && obj.getObjects) {
          const isSelectedInTree = obj.id === selectedTreeKey;
          // 允许整体拖动 layout 及其子 layer
          obj.set({
            hasControls: isSelectedInTree,
            hasBorders: isSelectedInTree,
            lockMovementX: !isSelectedInTree,
            lockMovementY: !isSelectedInTree,
            selectable: isSelectedInTree,
            evented: isSelectedInTree
          });
          // 子 layer 高亮
          obj.getObjects().forEach(child => {
            if (isSelectedInTree) {
              child.set({
                borderColor: '#FF9800', // 高亮橙色
                borderDashArray: [2, 2],
                stroke: '#FF9800',
                strokeWidth: 2
              });
            } else {
              child.set({
                borderColor: '#f2f2f2',
                borderDashArray: [5, 5],
                stroke: null,
                strokeWidth: 1
              });
            }
            // 子对象的 hasControls/hasBorders 仍按可见性
            child.set({
              hasControls: child.visible,
              hasBorders: child.visible
            });
          });
        }
      });
      this.canvas.requestRenderAll();
    }
  }
};
</script>

<style scoped>
.canvas-editor {
  display: flex;
  height: 100%;
}
.canvas-container {
  width: 50%;
  height: 100%;
  background-color: #ddd;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}
canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border: 1px solid #000;
  background: #fff;
}
.layer-container {
  width: 50%;
  height: 100%;
  border-left: 1px solid #ccc;
  padding: 0;
  background-color: #fff;
  display: flex;
  flex-direction: column;
}
.layer-panel {
  height: 100%;
  display: flex;
  flex-direction: column;
}
</style> 